package com.junmoo.www.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author dpwang
 */
@ToString
@EqualsAndHashCode(callSuper = false)
@Data
@Accessors(chain = true)
@TableName("sys_user")// 映射数据库表名
public class SysUser extends BasicEntity implements UserDetails {
    @TableId(value = "user_id",type = IdType.ASSIGN_ID)
    @JsonSerialize(using= ToStringSerializer.class)
    private Long id;

    private String username;

    private String password;

    private String salt;

    private String email;

    private String mobile;

    @TableField(exist = false)
    private Set<SysRole> roles;
    @TableField(exist = false)
    private Set<SysMenu> menus;
    @TableField(exist = false)
    private  Set<GrantedAuthority> authorities;
    @TableField(exist = false)
    private  boolean accountNonExpired;
    @TableField(exist = false)
    private  boolean accountNonLocked;
    @TableField(exist = false)
    private  boolean credentialsNonExpired;
    @TableField(exist = false)
    private  boolean enabled;
    public SysUser(){ }
    public SysUser( Long id,  String username, String password, List<String> authorities, boolean enabled ) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.authorities = mapToGrantedAuthorities(authorities);
        this.enabled = enabled;
    }
    public SysUser(Long id, String username, String password, String authoritie,boolean enabled) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.authorities = mapToGrantedAuthorities(authoritie);
        this.enabled = enabled;
    }


    public SysUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        this(username, password, true, true, true, true, authorities);
    }
    public SysUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
        Assert.isTrue(username != null && !"".equals(username) && password != null, "Cannot pass null or empty values to constructor");
        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpired = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
    }
    private Set<GrantedAuthority> mapToGrantedAuthorities(List<String> roles) {
        return Collections.unmodifiableSet( sortAuthorities(
                        roles.stream() .map(role -> new SimpleGrantedAuthority(role)) .collect(Collectors.toList())
                ));
    }
    private Set<GrantedAuthority> mapToGrantedAuthorities(String role) {
        return Collections.unmodifiableSet(  sortAuthorities(
                Arrays.asList(new SimpleGrantedAuthority(role))
        ));
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        if(StringUtils.hasText(this.username)){
            return this.username;
        }else if(StringUtils.hasText(this.mobile)){
            return this.mobile;
        }else if(StringUtils.hasText(this.email)){
            return this.email;
        }else{
            return null;
        }

    }

    @Override
    public boolean isAccountNonExpired() {
        return this.accountNonExpired;
    }

    @Override
    public boolean isAccountNonLocked() {
        return this.accountNonLocked;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return this.credentialsNonExpired;
    }

    @Override
    public boolean isEnabled() {
        return this.enabled;
    }

    private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
        SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet(new AuthorityComparator());
        Iterator var2 = authorities.iterator();

        while(var2.hasNext()) {
            GrantedAuthority grantedAuthority = (GrantedAuthority)var2.next();
            Assert.notNull(grantedAuthority, "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }

        return sortedAuthorities;
    }
    private static class AuthorityComparator implements Comparator<GrantedAuthority>, Serializable {
        private static final long serialVersionUID = 540L;

        private AuthorityComparator() {
        }
        @Override
        public int compare(GrantedAuthority g1, GrantedAuthority g2) {
            if (g2.getAuthority() == null) {
                return -1;
            } else {
                return g1.getAuthority() == null ? 1 : g1.getAuthority().compareTo(g2.getAuthority());
            }
        }
    }
}

